package myzd.services.impl;
import libedge.domain.exceptions.GenericException;
import libedge.utils.RetrofitUtils;
import lombok.extern.slf4j.Slf4j;
import myzd.api.code.CodeUtils;
import myzd.api.domain.ListResult;
import myzd.api.domain.PagedResult;
import myzd.api.domain.TreeResult;
import myzd.client.DoctorKbClient;
import myzd.client.GenericTradingServiceClient;
import myzd.client.QiniuClient;
import myzd.client.WeChatQiYeClient;
import myzd.client.domain.*;
import myzd.domain.*;
import myzd.domain.enums.ServiceTypeList;
import myzd.domain.request.*;
import myzd.domain.response.*;
import myzd.domain.response.PayPayment;
import myzd.domain.response.PaymentList;
import myzd.domain.response.RefundPayment;
import myzd.services.AuthorizationService;
import myzd.services.ClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @author zjm
 * @since 2017.10.23
 */
@Slf4j
@Component
public class DefaultClientServiceImpl implements ClientService {

  @Autowired
  private AuthorizationService authorizationService;

  @Autowired
  private DoctorKbClient doctorKbClient;

  @Autowired
  private WeChatQiYeClient weChatQiYeClient;

  @Autowired
  private GenericTradingServiceClient genericTradingServiceClient;

  @Autowired
  private QiniuClient qiniuClient;

  @Override
  public PagedResult<Hospital> getHospitalListByName(String hospitalName, Integer page, Integer pageSize) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getHospitalListByName(hospitalName, page, pageSize).execute());
    } catch (IOException e) {
      log.error("get hospitalList error. hospitalName: {}, message: {}", hospitalName, e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }
  @Override
  public PagedResult<Disease> getDiseaseListByDiseaseName(String diseaseName, Integer page, Integer pageSize) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getDiseaseListByDiseaseName(diseaseName, page, pageSize).execute());
    } catch (IOException e) {
      log.error("get diseaseList error. diseaseName: {}, message: {}", diseaseName, e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public PagedResult<DoctorDetailsDto> getDoctorList(String doctorName, String hospitalName, String diseaseName, Integer parentCategoryId,
                                                     Integer categoryId, Integer cityId, ServiceTypeList serviceType, Integer page, Integer pageSize) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getDoctorDetails(doctorName, hospitalName, diseaseName, parentCategoryId,
        categoryId, cityId, serviceType, page, pageSize).execute());
    } catch (IOException e) {
      log.error("get doctorDetailsList error. diseaseName: {}, message: {}", diseaseName, e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public PagedResult<City> getCityList(Integer provinceId, String cityName) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getCityList(provinceId, cityName, null).execute());
    } catch (IOException e) {
      log.error("get cityList error. provinceId: {} cityName{}, message: {}", provinceId, e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public PagedResult<Province> getProvinceList(String initial) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getProvinceList(initial).execute());
    } catch (IOException e) {
      log.error("get provinceList error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public ListResult<TreeResult<DiseaseCategory>> getAllDiseaseCategory() throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getAllDiseaseCategory().execute());
    } catch (IOException e) {
      log.error("get DiseaseCatagory error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public Hospital getHospitalById(Integer id) throws IOException, GenericException {
    checkIntegerPositive(id);
    Hospital hospital = RetrofitUtils.getResponseBody(doctorKbClient.getHospitalById(id).execute());
    if (hospital == null) {
      throw new GenericException(CodeUtils.ERROR_HOSPITAL_NOT_FOUND, CodeUtils.getErrText(CodeUtils.ERROR_HOSPITAL_NOT_FOUND));
    }
    return hospital;
  }

  @Override
  public Disease getDiseaseById(Integer id) throws GenericException, IOException {
    checkIntegerPositive(id);
    Disease disease = RetrofitUtils.getResponseBody(doctorKbClient.getDiseaseById(id).execute());
    if (disease == null) {
      throw new GenericException(CodeUtils.ERROR_DISEASE_NOT_FOUND, CodeUtils.getErrText(CodeUtils.ERROR_DISEASE_NOT_FOUND));
    }
    return disease;
  }

  @Override
  public City getCityById(Integer id) throws GenericException, IOException {
    checkIntegerPositive(id);
    City city = RetrofitUtils.getResponseBody(doctorKbClient.getCityById(id).execute());
    if (city == null) {
      throw new GenericException(CodeUtils.ERROR_CITY_NOT_FOUND, CodeUtils.getErrText(CodeUtils.ERROR_CITY_NOT_FOUND));
    }
    return city;
  }


  @Override
  public DoctorDetailsDto getDoctorById(Integer id) throws GenericException, IOException {
    checkIntegerPositive(id);
    DoctorDetailsDto doctorDetailsDto = RetrofitUtils.getResponseBody(doctorKbClient.getDoctorById(id).execute());
    if (doctorDetailsDto == null) {
      throw new GenericException(CodeUtils.ERROR_DOCTOR_NOT_FOUND, CodeUtils.getErrText(CodeUtils.ERROR_DOCTOR_NOT_FOUND));
    }
    return doctorDetailsDto;
  }

  @Override
  public ListResult<Department> getGroupList() throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(weChatQiYeClient.getGroupList().execute());
    } catch (IOException e) {
      log.error("get groupList error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public ListResult<QiYeEmployee> getUserList() throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(weChatQiYeClient.getUserList().execute());
    } catch (IOException e) {
      log.error("get userList error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public QiYeEmployee getUserByStaffId(String staffId) throws IOException, GenericException {
    QiYeEmployee qiYeEmployee = RetrofitUtils.getResponseBody(weChatQiYeClient.getUserByStaffId(staffId).execute());
    if (qiYeEmployee == null) {
      throw new GenericException(CodeUtils.ERROR_QIYE_USER_NOT_FOUND, CodeUtils.getErrText(CodeUtils.ERROR_QIYE_USER_NOT_FOUND));
    }
    return qiYeEmployee;
  }

  @Override
  public ServiceOrder createOrder(CreateAppointmentRequest createAppointmentRequest) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(genericTradingServiceClient.createOrder(createAppointmentRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder getOrderById(Long id) throws GenericException, IOException {
    checkLongPositive(id);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.getOrderById(id, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public PaymentList getOrderPaymentByOrderNumber(Long orderNumber) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.getOrderPaymentByOrderNumber(orderNumber, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ListResult<TrackDTO> listTracks(Long id) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.listTracks(id, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder addPayAccount(Long orderNumber, DoctorAccount doctorAccount) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(genericTradingServiceClient.addPayAccount(
        authorizationService.createCmsServiceToken(), orderNumber, doctorAccount).execute());
    } catch (IOException e) {
      log.error("add payAccount error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public List<Doctor> recommendDoctors(Long orderNumber, ListRequest<DoctorRequest> doctorListRequest) throws GenericException {
    log.debug("ListRequest<Doctor>.size: {},ListRequest<Doctor>: {}", doctorListRequest.getList().size(), doctorListRequest);
    try {
      List<DoctorRequest> doctorRequestList = RetrofitUtils.getResponseBody(genericTradingServiceClient.recommendDoctors(
        authorizationService.createCmsServiceToken(), orderNumber, doctorListRequest).execute()).getList();
      List<Doctor> doctorList = new ArrayList<>();
      doctorRequestList.forEach(doctor -> {
        Doctor targetDoctor = new Doctor();
        targetDoctor.setName(doctor.getDoctorName());
        targetDoctor.setMedicalTitleList(doctor.getDoctorMedicalTitle() == null ? null : doctor.getDoctorMedicalTitle().toString());
        targetDoctor.setId(Integer.valueOf(doctor.getDoctorId()));
        targetDoctor.setDepartment(doctor.getDoctorDepartment());
        targetDoctor.setHospitalId(doctor.getDoctorHospitalId());
        targetDoctor.setHospitalName(doctor.getDoctorHospitalName());
        doctorList.add(targetDoctor);
      });
      return doctorList;
    } catch (IOException e) {
      log.error("recommendDoctors error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public List<DoctorRequest> getDoctorsByIdList(List<Integer> doctorIds) throws GenericException {
    List<DoctorRequest> doctors = new ArrayList<>();
    try {
      doctorIds = doctorIds.stream().distinct().collect(Collectors.toList());
      for (Integer id : doctorIds) {
        DoctorDetailsDto doctorDetailsDto = RetrofitUtils.getResponseBody(doctorKbClient.getDoctorById(id).execute());
        if (doctorDetailsDto == null) {
          log.warn("no doctor,id: {}", id);
          continue;
        }
        doctors.add(new DoctorRequest() {{
          setDoctorDepartment(doctorDetailsDto.getDepartmentName());
          setDoctorHospitalName(doctorDetailsDto.getHospitalName());
          setDoctorHospitalId(doctorDetailsDto.getHospitalId());
          setDoctorId(String.valueOf(doctorDetailsDto.getId()));
          setDoctorName(doctorDetailsDto.getName());
          setDoctorMobile(doctorDetailsDto.getMobile());
          setDoctorMedicalTitle(doctorDetailsDto.getMedicalTitleList());
          setServiceTypeList(doctorDetailsDto.getServiceTypeList());
        }});
      }
      return doctors;
    } catch (IOException e) {
      log.error("add payAccount error.  message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }

  @Override
  public ServiceOrder updateOrder(Long orderNumber, ModifiedAppointmentRequest modifiedAppointmentRequest) throws GenericException, IOException {
    checkLongPositive(orderNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.updateOrder(orderNumber, modifiedAppointmentRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder assign(Long id, ChangeAssigneeRequest changeAssigneeRequest) throws GenericException, IOException {
    checkLongPositive(id);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.reassign(id, changeAssigneeRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder confirmedDoctor(Long orderNumber, ConfirmDoctorRequest confirmDoctorRequest) throws GenericException, IOException {
    checkLongPositive(orderNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.confirmedDoctor(orderNumber, confirmDoctorRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder completeOrder(Long orderNumber, CompleteOrderRequest completeOrderRequest) throws GenericException, IOException {
    checkLongPositive(orderNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.completeOrder(orderNumber, completeOrderRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public CreateReminderRequest createReminder(Long id, CreateReminderRequest createReminderRequest) throws GenericException, IOException {
    checkLongPositive(id);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.createReminder(id, createReminderRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public PostNotes createTrack(Long id, PostNotes postNotes) throws GenericException, IOException {
    checkLongPositive(id);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.createTrack(id, postNotes, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public PayPayment transfer(Long paymentNumber) throws GenericException, IOException {
    checkLongPositive(paymentNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.transfer(paymentNumber, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public RefundPayment refund(Long paymentNumber) throws GenericException, IOException {
    checkLongPositive(paymentNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.refund(paymentNumber, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServicePayment getByPaymentNumber(Long paymentNumber) throws GenericException, IOException {
    checkLongPositive(paymentNumber);
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.getByPaymentNumber(paymentNumber, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ListResult<UserMenu> getUserMenu(String staffId) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.getUserMenu(staffId, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ListResult<UserMenu> setUserMenu(String staffId, ListRequest<UserMenu> userMenuListRequest) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.setUserMenu(staffId, userMenuListRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public ServiceOrder cancelOrder(Long orderNumber, CancelOrderRequest cancelOrderRequest) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.cancelOrder(orderNumber, cancelOrderRequest, authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public PagedResult<Order> searchOrder(OrderSearchRequest orderSearchRequest) throws GenericException, IOException {
    return RetrofitUtils.getResponseBody(
      genericTradingServiceClient.searchOrder(
        orderSearchRequest.getExcludeAppointmentStatus(),
        orderSearchRequest.getExcludeAssigneeId(),
        orderSearchRequest.getCreatorId(),
        orderSearchRequest.getIsAssigned(),
        orderSearchRequest.getAssigneeId(),
        orderSearchRequest.getAssigneeDepartment(),
        orderSearchRequest.getPreviousAssigneeId(),
        null,
        null,
        orderSearchRequest.getCompleteAssigneeId(),
        orderSearchRequest.getId(),
        orderSearchRequest.getOrderNumber(),
        orderSearchRequest.getPatientName(),
        orderSearchRequest.getPatientPhone(),
        orderSearchRequest.getCreatedAt(),
        orderSearchRequest.getServiceType(),
        orderSearchRequest.getOrderByType(),
        orderSearchRequest.getOrderStatus(),
        orderSearchRequest.getAppointmentStatus(),
        orderSearchRequest.getHideTest(),
        orderSearchRequest.getPage(),
        orderSearchRequest.getPageSize(),
        authorizationService.createCmsServiceToken()).execute()
    );
  }

  @Override
  public UploadTokenV2 getFileTokenV2(int type, String fileName, Long sizeLimit, String MIME) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(
        qiniuClient.getFileTokenV2(type, fileName, sizeLimit, MIME).execute()
      );
    } catch (IOException e) {
      log.error("get fileTokenV2 error, message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_GET_FILE_TOKEN, CodeUtils.getErrText(CodeUtils.ERROR_GET_FILE_TOKEN));
    }
  }

  @Override
  public UploadToken getFileToken(int type, String fileName, Integer sizeLimit, String MIME) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(
        qiniuClient.getFileToken(type, fileName, sizeLimit, MIME).execute()
      );
    } catch (IOException e) {
      log.error("get fileToken error, message: {}", e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_GET_FILE_TOKEN, CodeUtils.getErrText(CodeUtils.ERROR_GET_FILE_TOKEN));
    }
  }


  @Override
  public ListResult<QiYeEmployee> listUsersInDepartment(int departmentId, Boolean inService) throws IOException, GenericException {
    return RetrofitUtils.getResponseBody(
      weChatQiYeClient.listUsersInDepartment(departmentId, inService).execute()
    );
  }

  private void checkIntegerPositive(Integer i) throws GenericException {
    if (i == null || i <= 0) {
      throw new GenericException(CodeUtils.ERROR_WRONG_PARAMETERS, CodeUtils.getErrText(CodeUtils.ERROR_WRONG_PARAMETERS));
    }
  }

  private void checkLongPositive(Long i) throws GenericException {
    if (i == null || i <= 0) {
      throw new GenericException(CodeUtils.ERROR_WRONG_PARAMETERS, CodeUtils.getErrText(CodeUtils.ERROR_WRONG_PARAMETERS));
    }
  }

  @Override
  public PagedResult<Counties> getCountryByCityId(Integer cityId) throws GenericException {
    try {
      return RetrofitUtils.getResponseBody(doctorKbClient.getCountryByCityId(cityId).execute());
    } catch (IOException e) {
      log.error("get CountryList error. cityId;{}, message: {}", cityId, e.getMessage(), e);
      throw new GenericException(CodeUtils.ERROR_SERVICE_CONNECT, CodeUtils.getErrText(CodeUtils.ERROR_SERVICE_CONNECT));
    }
  }


}
